/*****************************************************
*                                                                          
*               COPYRIGHT (c) 2015-2017 Hargic Corporation                 
*                         All Rights Reserved                              
*                                                                          
* The source code contained or described herein and all documents          
* related to the source code ("Material") are owned by Hargic            
* Corporation or its licensors.  Title to the Material remains             
* with Hargic Corporation or its suppliers and licensors.                  
*                                                                          
* The Material is protected by worldwide copyright and trade secret        
* laws and treaty provisions. No part of the Material may be used,         
* copied, reproduced, modified, published, uploaded, posted, transmitted,  
* distributed, or disclosed in any way except in accordance with the       
* applicable license agreement.                                            
*                                                                          
* No license under any patent, copyright, trade secret or other            
* intellectual property right is granted to or conferred upon you by       
* disclosure or delivery of the Materials, either expressly, by            
* implication, inducement, estoppel, except in accordance with the         
* applicable license agreement.                                            
*                                                                          
* Unless otherwise agreed by Hargic in writing, you may not remove or      
* alter this notice or any other notice embedded in Materials by Hargic    
* or Hargic's suppliers or licensors in any way.                           
*                                                                          
** Author: shengda.huang
** Date: 2018-11-24
*
*****************************************************/

/***** Include files ********************************/
#include <stdio.h>
#include <string.h>
#include "sys_shell.h"
#include "ringbuffer.h"

/***** Defines **************************************/
#define tc_log(_fmt_, ...)   printf("[TC][%s:%d][%s] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)

/***** Define structure *****************************/

/***** Define constant ******************************/

/***** Define global ********************************/
ringbuffer_t rb_ctx;
unsigned char rb_init = 0;

/***** Define Prototype of functions ****************/

/**
 * @brief
 * @param  None
 * @retval None
 */
static void hex_dump(char *desc, unsigned char *data, int len)
{
    unsigned int i;

    printf("%s size %d hex dump:", desc, len);
    for(i=0; i<len; i++)
    {
        if (i % 32 == 0)
            printf("\n");
        printf(" %02x", data[i]);
    }
    printf("\n");
}

static void ringbuff_shell_help(char *cmd)
{
    tc_log("USAGE");
    tc_log("    %s [option] ", cmd);
    tc_log("    -h         help");
    tc_log("    -C [deep]  create the ringbuffer with deep size");
    tc_log("    -D         distory the ringbuffer");
    tc_log("    -d         dump ringbuffer");
    tc_log("    -w [len]   write len bytes into ringbuffer");
    tc_log("    -r [len]   read len bytes from ringbuffer");
    tc_log("    -c [len]   consume len bytes from ringbuffer");
    tc_log("EXAMPLE");
    tc_log("'%s -h'", cmd);
    tc_log("'%s -C 1024'", cmd);
    tc_log("'%s -D'", cmd);
    tc_log("'%s -d'", cmd);
    tc_log("'%s -w 32'", cmd);
    tc_log("'%s -r 64'", cmd);
    tc_log("'%s -c 64'", cmd);
    tc_log(" ");
}

static int ringbuff_shell_create(char *cmd, int deepsize)
{
    if (rb_init != 0)
    {
        tc_log("ringbuffer has initialized");
        return -1;
    }

    memset(&rb_ctx, 0x0, sizeof(ringbuffer_t));

    unsigned char *buff = NULL;
    buff = malloc(deepsize);
    if (buff == NULL)
    {
        tc_log("create ringbuffer failed");
        return -1;
    }

    int ret = ringbuffer_init(&rb_ctx, buff, deepsize);
    if (ret == 0)
    {
        rb_init = !0;
        tc_log("ringbuffer initialize success");
    }
    else
    {
        tc_log("ringbuffer initialize failed");
    }
    return ret;
}

static int ringbuff_shell_distory(char *cmd)
{
    if (rb_init == 0)
    {
        tc_log("ringbuffer has not initialized");
        return -1;
    }

    free(rb_ctx.buffer);
    int ret = ringbuffer_deinit(&rb_ctx);
    if (ret == 0)
    {
        rb_init = 0;
        tc_log("ringbuffer distory success");
    }
    else
    {
        tc_log("ringbuffer distory failed");
    }
    return ret;
}

static int ringbuff_shell_dump(char *cmd)
{
    ringbuffer_info(&rb_ctx);
    ringbuffer_dump(&rb_ctx, 0, rb_ctx.size);
    return 0;
}

static int ringbuff_shell_write(char *cmd, int len)
{
    unsigned char *buff;
    int i, freesize, to_write, wrotten;

    if (len <= 0)
    {
        tc_log("write len %d err", len);
        return -1;
    }

    if (rb_init == 0)
    {
        tc_log("ringbuffer has not initialized");
        return -1;
    }

    freesize = ringbuffer_free_space(&rb_ctx);
    to_write = min(freesize, len);
    if (to_write != len)
        tc_log("freesize %d want to write %d actually to write %d", freesize, len, to_write);

    if (to_write <= 0)
    {
        tc_log("write size %d err", to_write);
        return -2;
    }

    buff = malloc(to_write);

    buff[0] = 0x3c;
    for (i=1; i<to_write; i++)
        buff[i] = i;

    wrotten = ringbuffer_write(&rb_ctx, buff, to_write);
    if (wrotten != to_write)
    {
        tc_log("wrotten size %d not match need size %d", wrotten, to_write);
        return -3;
    }
    hex_dump("wrote", buff, to_write);

    free(buff);
    return 0;
}

static int ringbuff_shell_read(char *cmd, int len)
{
    int usedsize, to_read;

    if (len <= 0)
    {
        tc_log("read len %d err", len);
        return -1;
    }

    if (rb_init == 0)
    {
        tc_log("ringbuffer has not initialized");
        return -1;
    }

    usedsize = ringbuffer_used_space(&rb_ctx);
    to_read = min(usedsize, len);
    if (to_read != len)
        tc_log("usedsize %d want to read %d actually to read %d", usedsize, len, to_read);

    unsigned char *available_data;
    unsigned int bytes_available;

    ringbuffer_get_data(&rb_ctx, &available_data, &bytes_available);
    if (to_read != bytes_available)
        tc_log("to read %d bytes available %d", to_read, bytes_available);

    hex_dump("read", available_data, min(to_read, bytes_available));
    return 0;
}

static int ringbuff_shell_consume(char *cmd, int len)
{
    int usedsize, to_consume;

    if (len <= 0)
    {
        tc_log("consume len %d err", len);
        return -1;
    }

    if (rb_init == 0)
    {
        tc_log("ringbuffer has not initialized");
        return -1;
    }

    usedsize = ringbuffer_used_space(&rb_ctx);
    to_consume = min(usedsize, len);
    if (to_consume != len)
        tc_log("usedsize %d want to consume %d actually to consume %d", usedsize, len, to_consume);

    return ringbuffer_consume(&rb_ctx, to_consume);
}

static int ringbuff_shell_freespace(char *cmd)
{
    tc_log("freespace %d", ringbuffer_free_space(&rb_ctx));
}

static int ringbuff_shell_usedspace(char *cmd)
{
    tc_log("usedspace %d", ringbuffer_used_space(&rb_ctx));
}

static int ringbuff_shell_handler(int argc, char **argv)
{
    int c = 0;
    int value;

    if(argc == 1)
    {
        ringbuff_shell_help(argv[0]);
        return -1;
    }

    optind = 0;
    opterr = 0;
    while((c = getopt(argc, argv, "C:Ddw:r:c:fu")) != -1)
    {
        switch(c)
        {
            case 'h':
                ringbuff_shell_help(argv[0]);
                break;
            case 'C':
                value = atoi(optarg);
                ringbuff_shell_create(argv[0], value);
                break;
            case 'D':
                ringbuff_shell_distory(argv[0]);
                break;
            case 'd':
                ringbuff_shell_dump(argv[0]);
                break;
            case 'w':
                value = atoi(optarg);
                ringbuff_shell_write(argv[0], value);
                break;
            case 'r':
                value = atoi(optarg);
                ringbuff_shell_read(argv[0], value);
                break;
            case 'c':
                value = atoi(optarg);
                ringbuff_shell_consume(argv[0], value);
                break;
            case 'f':
                ringbuff_shell_freespace(argv[0]);
                break;
            case 'u':
                ringbuff_shell_usedspace(argv[0]);
                break;
        }
    }

    return 0;
}

int main(int argc, char **argv)
{
    char cmd[64];
    int ret;

    tc_log("### TestCase 1 test ringbuffer manually by shell ###");

    sys_shell_init();

    sys_shell_register("ringbuff", "ringbuffer operation", ringbuff_shell_handler);

    while (1)
    {
        gets(cmd);
        ret = sys_shell_handler(cmd, strlen(cmd));
        if (ret == SYS_SHELL_EXIT)
            break;
    }

    if (rb_init != 0)
    {
    	free(rb_ctx.buffer);
    	ringbuffer_deinit(&rb_ctx);
    }
    
    tc_log("exit");
    return 0;
}

/* End of file */



